package my.framework.web;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.print.DocFlavor;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 用于加载Controller映射信息
 *
 */
public class ControllerMappingManager {

    /**
     * 创建一个hashMap集合，key--绝对url(具体到某个方法)，
     * value--是ControllerMapping对象，存1--指定控制器的完整名称(类名+包名),存2--此控制器中某一方法的名字
     * 由此，获取到key后就可得到指定控制器中的指定方法的操作
     */
    private Map<String, ControllerMapping> controllerMappings = new HashMap<String, ControllerMapping>();

    /**
     * 构造方法
     *
     * @param configFileName
     *            配置文件名
     */
    public ControllerMappingManager(String configFileName) {
        //调用自定义的初始化方法--根据配置文件名，解析文件，并将得到的数据存入controllerMappings集合
        init(configFileName);
    }

    /**
     * init方法用来加载Controller配置文件。
     *
     * @param configFileName
     *            配置文件名
     */
    public void init(String configFileName) {
        InputStream is = this.getClass().getResourceAsStream("/" + configFileName);
        Document doc;
        try {
            doc = new SAXReader().read(is);
        } catch (DocumentException e) {
            throw new ConfigLoadingException(e);
        }
        Element root = doc.getRootElement();
        Iterator<Element> controllersIt = root.elements("controllers").iterator();
        Element controllersEl = controllersIt.next();
        for (Iterator<Element> controllerIt = controllersEl.elementIterator("controller"); controllerIt.hasNext();) {
            Element controller = controllerIt.next();
            String firstPath = controller.attributeValue("path");
            String className = controller.attributeValue("class");
            if (className.isEmpty())
                throw new ConfigException("Controller的映射信息不能为空！");
            ControllerMapping mapping = null;
            for (Iterator<Element> methodIt = controller.elementIterator("method"); methodIt.hasNext();) {
                Element method = methodIt.next();
                String secondPath = method.attributeValue("path");
                String methodName = method.getText();
                if (methodName.isEmpty())
                    throw new ConfigException("方法的映射信息不能为空！");
                String fullPath = (firstPath + secondPath).replaceAll("//", "/");
                if (controllerMappings.containsKey(fullPath)) {
                    mapping = controllerMappings.get(fullPath);
                    throw new ConfigException("不能将路径 " + fullPath + " 映射到 " + className + "." + methodName + "()\n路径 "
                            + fullPath + " 已被 " + mapping.getClassName() + "." + mapping.getMethodName() + "() 映射");
                }
                //将得到的方法名，完整类名赋值给ControllerMapping对象的相应属性
                mapping = new ControllerMapping(className, methodName);
                //将得到的完整路径，配置文件信息对象（完整类名，方法名）存入controllerMappings集合
                controllerMappings.put(fullPath, mapping);
                System.out.println("================================map " + fullPath + " to " + className + "."
                        + methodName + "()"); // log
            }
        }
    }

    /**
     * 根据映射信息查询对应的ControllerMapping实例。
     *
     * @param path
     * @return ControllerMapping
     */
    public ControllerMapping getControllerMapping(String path) {
        return this.controllerMappings.get(path);
    }

    /**
     * 判断是否存在对应的映射信息。
     *
     * @param path
     * @return
     */
    public boolean containsKey(String path) {
        return this.controllerMappings.containsKey(path);
    }

    /**
     * @return 返回所有Controller映射信息
     */
    public Map<String, ControllerMapping> getControllerMappings() {
        return this.controllerMappings;
    }
}
